using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;

using FreeFlow.Client;
using FreeFlow.Client.Events;
using FreeFlow.WinFormsControls.HelperClasses;
using System.Drawing.Imaging;

namespace FreeFlow.WinFormsControls
{
	/// <summary>
	/// Control to render a form.
	/// </summary>
	public class FormControl : System.Windows.Forms.UserControl
	{
    private System.ComponentModel.IContainer components;
    private System.Windows.Forms.ErrorProvider errorProvider;
    private System.Windows.Forms.ToolTip toolTip;

    /// <summary>
    /// Creates a new <see cref="FormControl"/> instance.
    /// </summary>
		public FormControl()
		{
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(components != null)
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Component Designer generated code
		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
      this.components = new System.ComponentModel.Container();
      this.toolTip = new System.Windows.Forms.ToolTip(this.components);
      this.errorProvider = new System.Windows.Forms.ErrorProvider();
      // 
      // errorProvider
      // 
      this.errorProvider.ContainerControl = this;
      // 
      // FormControl
      // 
      this.AutoScroll = true;
      this.Name = "FormControl";
      this.Size = new System.Drawing.Size(472, 240);

    }
		#endregion
    #region button operations
    private void button_Click(object sender, EventArgs e)
    {
      Button button = sender as Button;
      ButtonField buttonField = form.Field(button.Name) as ButtonField;
      switch(buttonField.Operation)
      {
        case ButtonOperation.Submit :
          if (SubmitForm != null)
            SubmitForm(this, e);
          break;
        case ButtonOperation.Cancel :
          if (CancelForm != null)
            CancelForm(this, e);
          break;
        case ButtonOperation.Server :
          OnRefillForm(sender);
          break;
        case ButtonOperation.Folder :
          if (OpenFolder != null)
            if (buttonField.OpenFolderId.Length > 0)
              OpenFolder(this, new OpenFolderEventArgs(buttonField.OpenFolderId));
          break;
        case ButtonOperation.BlankForm :
          if (OpenBlankForm != null)
            OpenBlankForm(this, new OpenBlankFormEventArgs(buttonField.BlankFormProcess, 
              buttonField.BlankFormAction));
          break;
        case ButtonOperation.Client :
          ExecuteScripts(buttonField.ClientScriptEvents, ClientScriptEventName.OnClick);
          break;
        default :
          throw new FreeFlowException("Unrecognized button operation - " + buttonField.Operation.ToString());
      }
    }

    private static void ExecuteScripts(ClientScriptEvents scriptEvents, string scriptEventName)
    {
      for (int i = 0; i < scriptEvents.Count; i++)
      {
        if (scriptEvents[i].EventName == scriptEventName)
          ExecuteScript(scriptEvents[i]);
      }
    }

    private static void ExecuteScript(ClientScriptEvent script)
    {
      // TODO - implement
    }

    /// <summary>
    /// Event triggered when the user presses a button that submits the form.
    /// </summary>
    [Description("Event triggered when the user presses a button that submits the form.")]
    [Category(Constants.FreeFlowCategory)]
    public event EventHandler SubmitForm;

    /// <summary>
    /// Event triggered when the user presses a button that cancels the form.
    /// </summary>
    [Description("Event triggered when the user presses a button that cancels the form.")]
    [Category(Constants.FreeFlowCategory)]
    public event EventHandler CancelForm;

    /// <summary>
    /// Event triggered when the user presses a button that opens a blank form.
    /// </summary>
    [Description("Event triggered when the user presses a button that opens a blank form.")]
    [Category(Constants.FreeFlowCategory)]
    public event EventHandler<OpenBlankFormEventArgs> OpenBlankForm;

    /// <summary>
    /// Event triggered when the user presses a button that opens a folder.
    /// </summary>
    [Description("Event triggered when the user presses a button that opens a folder.")]
    [Category(Constants.FreeFlowCategory)]
    public event EventHandler<OpenFolderEventArgs> OpenFolder;

    #endregion
    #region refills
    
    private void OnRefillForm(object sender)
    {
      using (new CursorHandler())
      {
        if (RefillForm != null)
          RefillForm(sender, new RefillFormEventArgs((sender as Control).Name));
      }
    }

    /// <summary>
    /// Event triggered when the form should be refilled.
    /// </summary>
    [Description("Event triggered when the form should be refilled.")]
    [Category(Constants.FreeFlowCategory)]
    public event EventHandler<RefillFormEventArgs> RefillForm;
      
    private void FormControl_Refill(object sender, EventArgs e)
    {
      OnRefillForm(sender);
    }

    #endregion
    #region event handlers
    private void grid_Click(object sender, EventArgs e)
    {
      GridControl gridControl = (GridControl)sender;
      GridField gridField = (GridField)form.Field(gridControl.Name);
      
      if (gridField.GridType == GridType.Folder)
      {
        if (gridControl.SelectedRow != null)
        {
          string folderId = gridControl.SelectedRow["eFolderID"].ToString();
          if (OpenFolder != null)
            OpenFolder(this, new OpenFolderEventArgs(folderId));
        }
      }
      else if (gridField.GridType == GridType.Refill)
      {
        OnRefillForm(sender);
      }
    }

    private void status_Click(object sender, EventArgs e)
    {
      StatusControl statusControl = (StatusControl)sender;
      StatusField statusField = (StatusField)form.Field(statusControl.Name);

      if ((statusField.Url != null) && (statusField.Url.ToString().Length > 0))
      {
        // open a URL
        Process.Start(statusField.Url.ToString());
      }
      else if ((statusField.Process != null) && (statusField.Process.Length > 0))
      {
        // start a blank form
        if (OpenBlankForm != null)
          OpenBlankForm(this, new OpenBlankFormEventArgs(statusField.Process, statusField.Action));
      }
    }

    #endregion

    private FreeFlow.Client.Form form;
    /// <summary>
    /// Populates the control with the specified form and fills the fields with the form's values.
    /// </summary>
    /// <param name="form">Form.</param>
    public void Populate(FreeFlow.Client.Form form)
    {
      CreateControls(form);
      PopulateControls(form);
    }

    /// <summary>
    /// Populates the controls with the form's values.
    /// </summary>
    /// <param name="form">Form.</param>
    public void PopulateControls(FreeFlow.Client.Form form)
    {
      if (form != null)
      {
        foreach (Control control in Controls)
        {
          Field field = form.Field(control.Name);
          if (field != null)
          {
            if (control is IFillable)
            {
              ((IFillable)control).Fill(field);
            }
            else
              throw new FreeFlowException("Unrecognized control - " + control.GetType().Name);
          }
        }
      }
    }

    private Control CreateControl(Field field)
    {
      Control control = null;

      if (field is RuleField)
        control = new RuleControl();
      else if (field is LabelField)
        control = new LabelControl();
      else if (field is TextField)
        control = new TextControl();
      else if (field is MemoField)
        control = new MemoControl();
      else if (field is DropDownField)
        control = new DropDownControl();
      else if (field is DateTimeField)
        control = new DateTimeControl();
      else if (field is CheckField)
        control = new CheckBoxControl();
      else if (field is ButtonField)
      {
        control = new ButtonControl();
        (control as ButtonControl).Click += new EventHandler(button_Click);
      }
      else if (field is ListField)
        control = new ListControl();
      else if (field is NumberField)
        control = new NumberControl();
      else if (field is CurrencyField)
        control = new CurrencyControl();
      else if (field is RadioGroupField)
        control = new RadioGroupControl();
      else if (field is ImageField)
        control = new ImageControl();
      else if (field is GridField)
      {
        control = new GridControl();
        control.Click += new EventHandler(grid_Click);
      }
      else if (field is AttachmentField)
        control = new AttachmentControl();
      else if (field is StatusField)
      {
        control = new StatusControl();
        control.Click += new EventHandler(status_Click);
      }
      else if (field is SignatureField)
        control = new SignatureControl();
      else
        throw new FreeFlowException("Unrecognized field - " + field.GetType().Name);

      return control;
    }

    private void CreateControls(FreeFlow.Client.Form form)
    {
      this.form = form;
      if (form != null)
      {
        BackColor = form.Color;
        Font = form.Font;
        ForeColor = form.FontColor;

        Controls.Clear();

        for (int i = 0; i < form.FieldCount; i++)
        {
          Field field = form.Field(i);

          Control control = CreateControl(field);

          if (control != null)
          {
            if (field.Usage == FieldUsage.Required)
            {
              // TODO - red border
            }
            else if (field.Usage == FieldUsage.Hidden)
              control.Visible = false;
            else if (field.Usage == FieldUsage.ReadOnly)
              MakeFieldReadOnly(control);

            // hide labels attached to fields
            if (field is LabelField)
            {
              string attachedFieldName = (field as LabelField).LinkField;
              Field attachedField = null;
              if (attachedFieldName != null)
                attachedField = form.Field(attachedFieldName);
              if (attachedField != null)
                if (attachedField.Usage == FieldUsage.Hidden)
                  control.Visible = false;
            }

            Controls.Add(control);
            control.BringToFront();
            control.Top = field.Top;
            control.Left = field.Left;
            if (field.Width > 0)
              control.Width = field.Width;
            if (field.Height > 0)
              control.Height = field.Height;
            control.Name = field.Name;
            toolTip.SetToolTip(control, field.Hint);

            if (control is IFillable)
              (control as IFillable).Render(field);

            if (field.AutoRefill)
              if (control is IRefillable)
                ((IRefillable)control).Refill += new EventHandler(FormControl_Refill);
          }
        }
      }
    }

    /// <summary>
    /// Validates the fields on the form.
    /// </summary>
    /// <returns>True if there are no validation errors.</returns>
    public bool ValidateFields()
    {
      bool retVal = true; 
      if (form != null)
      {
        foreach (Control control in Controls)
        {
          Field field = form.Field(control.Name);
          if (field != null)
          {
            if ((field.Usage != FieldUsage.Hidden) && (field.Usage != FieldUsage.ReadOnly))
            {
              string error = field.GetValidationMessage();
              if (error != null)
                retVal = false;
              errorProvider.SetError(control, error);
            }
          }
        }
      }
      return retVal;
    }

    /// <summary>
    /// Updates the underlying form values from the control.
    /// </summary>
    /// <param name="form">Form.</param>
    public void UpdateFormValues(FreeFlow.Client.Form form)
    {
      if (form != null)
      {
        // add field values
        foreach (Control control in Controls)
        {
          Field field = form.Field(control.Name);
          if (field != null)
          {
            if (control is IFillable)
              ((IFillable)control).FillField(field);
            else
              throw new FreeFlowException("Unrecognized field - " + control.GetType().Name);
          }
        }
      }
    }

    /// <summary>
    /// Makes all the fields on the form read-only.
    /// </summary>
    public void MakeFieldsReadOnly()
    {
      foreach (Control control in Controls)
      {
        MakeFieldReadOnly(control);
      }
    }

    private static void MakeFieldReadOnly(Control control)
    {
      if (control is TextBox)
      {
        TextBox textBox = (TextBox)control;
        textBox.ReadOnly = true;
        textBox.BorderStyle = BorderStyle.FixedSingle;
        textBox.BackColor = SystemColors.Window;
      }
      else if (control is ComboBox)
      {
        control.Enabled = false;
      }
      else if (control is CheckBox)
      {
        control.Enabled = false; 
      }
      else if (control is GridControl)
      {
        (control as GridControl).ReadOnly = true;
      }
      else if (control is Button)
      {
        control.Enabled = false;
      }
      else if (control is DateTimePicker)
      {
        control.Enabled = false;
      }
      else if (control is ListBox)
      {
        control.Enabled = false;
      }
      else if (control is LabelControl)
      {
        // do nothing
      }
      else if (control is RuleControl)
      {
        // do nothing
      }
      else if (control is AttachmentControl)
      {
        (control as AttachmentControl).ReadOnly = true;
      }
      else if (control is PictureBox)
      {
        // do nothing
      }
      else if (control is RadioGroupControl)
      {
        control.Enabled = false;
      }
      else
        throw new FreeFlowException("Unrecognized field - " + control.GetType().Name);
    }

    /// <summary>
    /// Gets the preferred size of the control.
    /// </summary>
    public Size PreferredControlSize
    {
      get
      {
        if (form != null)
          return form.Size;

        return Size;
      }
    }
	}
}
